﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<thread>
#include <ctime>
#include <ratio>
#include <chrono>                      
using namespace std;


//异常在try catch内部才可以捕捉
//通过抛出(throw)⼀个对象来引发⼀个异常，该对象的类型以及当前的调⽤链决定了应该由哪个catch的处理代码来处理该异常。
//例如抛的是int ,则用int捕获
//匹配规则:   .........
//double Division(int a, int b)
//{
//	// 当b == 0时抛出异常
//	if (b == 0)
//	{
//		string s("Division by zero condition!");
//		throw s;//没有trt catch 这个函数结束去下一个函数
//	}
//	else
//	{
//		return ((double)a / (double)b);
//	}
//}
//
//void Func()
//{
//	int len, time;
//	cin >> len >> time;
//
//	try
//	{
//		cout << Division(len, time) << endl;//有trt catch,不匹配继续向下,直到匹配为之
//	}
//	catch (size_t x)
//	{
//		cout << x << endl;
//	}
//	catch (const char* errmsg)
//	{
//		cout << errmsg << endl;
//	}
//}
//
//int main()
//{
//	while (1)
//	{
//		try
//		{
//			Func();
//		}
//		catch (const string* errmsg)
//		{
//			cout << errmsg << endl;
//		}
//		catch (...)
//		{
//			cout << "unkown exception" << endl;//捕获未知异常
//		}
//	}
//	return 0;
//}


//异常包括:错误id和错误信息
// 服务器开发中通常使用的是异常继承体系
class Exception//基类

{
public:
	Exception(const string& errmsg, int id)
		:_errmsg(errmsg)//错误信息内容
		, _id(id)//错误编号
	{}

	virtual string what() const//仿函数
	{
		return _errmsg;
	}

	int getid() const
	{
		return _id;
	}

protected:
	string _errmsg;
	int _id;
};

class SqlException : public Exception//继承父类
{
public:
	SqlException(const string& errmsg, int id, const string& sql)//数据库
		:Exception(errmsg, id)
		, _sql(sql)
	{}

	virtual string what() const
	{
		string str = "SqlException:";
		str += _errmsg;
		str += "->";
		str += _sql;
		return str;
	}
private:
	const string _sql;
};

class CacheException : public Exception//缓存
{
public:
	CacheException(const string& errmsg, int id)
		:Exception(errmsg, id)
	{}

	virtual string what() const
	{
		string str = "CacheException:";
		str += _errmsg;
		return str;
	}
};

class HttpServerException : public Exception//网络请求
{
public:
	HttpServerException(const string& errmsg, int id, const string& type)
		:Exception(errmsg, id)
		, _type(type)
	{}

	virtual string what() const
	{
		string str = "HttpServerException:";
		str += _type;
		str += ":";
		str += _errmsg;
		return str;
	}

private:
	const string _type;
};

void SQLMgr()
{
	if (rand() % 7 == 0)
	{
		throw SqlException("权限不足", 100, "select * from name = '张三'");
	}

	cout << "调用成功" << endl;
}

void CacheMgr()
{
	if (rand() % 5 == 0)
	{
		throw CacheException("权限不足", 100);
	}
	else if (rand() % 6 == 0)
	{
		throw CacheException("数据不存在", 101);
	}
	SQLMgr();
}

void seedmsg(const string& s)
{
	//cout << "void seedmsg(const string& s)" << endl;

	//throw HttpServerException("网络不稳定，发送失败", 102, "put");

	if (rand() % 2 == 0)
	{
		throw HttpServerException("网络不稳定，发送失败", 102, "put");
	}
	else if (rand() % 3 == 0)
	{
		throw HttpServerException("你已经不是对象的好友，发送失败", 103, "put");
	}
	else
	{
		cout << "发送成功" << endl;
	}
}

void HttpServer()
{
	/*if (rand() % 3 == 0)
	{
		throw HttpServerException("请求资源不存在", 100, "get");
	}
	else if (rand() % 4 == 0)
	{
		throw HttpServerException("权限不足", 101, "post");
	}*/

	// 失败以后，再重试3次
	for (size_t i = 0; i < 4; i++)//请求一次,尝试3次,所以i<4;
	{
		try
		{
			seedmsg("今天一起看电影吧");
			break;
		}
		catch (const Exception& e)
		{
			if (e.getid() == 102)
			{
				if (i == 3)
					throw e;

				cout << "开始第" << i + 1 << "重试" << endl;
			}
			else
			{
				throw e;//异常重新抛出异常情况1
			}
		}
	}
	CacheMgr();
}

//int main()
//{
//	srand(time(0));
//
//	while (1)
//	{
//		this_thread::sleep_for(chrono::seconds(1));
//
//		try 
//		{
//			HttpServer();
//		}
//		catch (const Exception& e) // 这里捕获父类对象就可以
//		{
//			using std::chrono::system_clock;
//			// 多态
//			system_clock::time_point today = system_clock::now();
//			std::time_t tt = system_clock::to_time_t(today);
//			cout << ctime(&tt) << e.what() << endl << endl;
//		}
//		catch (...)
//		{
//			cout << "Unkown Exception" << endl;
//		}
//	}
//
//	return 0;
//}

//异常重新抛出(上述为情况1)
//情况2(异常安全问题)
//前⾯申请了资源(内存、锁等)，后⾯进⾏释放，但是中间可
//能会抛异常就会导致资源没有释放，这⾥由于异常就引发了资源泄漏，产⽣安全性的问题。
//double Divide(int a, int b)
//{
//	// 当b == 0时抛出异常
//		if (b == 0)
//		{
//			throw "Division by zero condition!";
//		}
//	return (double)a / (double)b;
//}
//void Func()
//{
//	// 这⾥可以看到如果发⽣除0错误抛出异常，另外下⾯的array没有得到释放。
//
//	// 所以这⾥捕获异常后并不处理异常，异常还是交给外层处理，这⾥捕获了再重新抛出去。
//
//		int* array = new int[10];
//	try
//	{
//		int len, time;
//		cin >> len >> time;
//		cout << Divide(len, time) << endl;
//	}
//	catch (...)
//	{
//		// 捕获异常释放内存
//		cout << "delete []" << array << endl;
//		delete[] array;
//		throw; // 异常重新抛出，    捕获到什么抛出什么
//	}
//	cout << "delete []" << array << endl;
//	delete[] array;
//}
//int main()
//{
//	try
//	{
//		Func();
//	}
//	catch (const char* errmsg)
//	{
//		cout << errmsg << endl;
//	}
//	catch (const exception& e)
//	{
//		cout << e.what() << endl;
//	}
//	catch (...)
//	{
//		cout << "Unkown Exception" << endl;
//	}
//	return 0;
//}


